#include "common.h"


int server = 0;
char hostname[20];
int port = 8000;
int length = 65536;
int number = 8192;

struct session {
	int number;
	int length;
};

struct message {
	int length;
	char data[0];
};

static void server_routine();
static void client_routine();


int main(int argc, char* argv[]) {
	Args args = parsecmdline(argc, argv);
  if (args.empty() || args.find("h") == args.end()) {
		printf("Usage: %s <-s> <-h hostname> [-p port] [-l length] [-n number]\n", argv[0]);
		return 1;
	}

	strcpy(hostname, args["h"].c_str());
	if (args.find("s") != args.end()) server = 1;
	if (args.find("p") != args.end()) port = atoi(args["p"].c_str());
	if (args.find("l") != args.end()) length = atoi(args["l"].c_str());
	if (args.find("n") != args.end()) number = atoi(args["n"].c_str());


	if (server) {
		server_routine();
	}
	else {
		client_routine();
	}
	return 0;
}

static void server_routine() {
	int ret, listenfd, clientfd, i, ack, reuse;
  struct sockaddr_in servaddr, cliaddr;
	socklen_t servaddrlen, cliaddrlen;
	char *buf;
	struct session ss;
	struct message *msg;
	
	servaddr = resolve(hostname, port);
	servaddrlen = sizeof(servaddr);

	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	if (listenfd < 0) ERR_EXIT("socket");

	reuse = 1;
	ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
	if (ret < 0) ERR_EXIT("reuse addr");

	ret = bind(listenfd, (struct sockaddr*)&servaddr, servaddrlen);
	if (ret < 0) ERR_EXIT("bind");

	ret = listen(listenfd, 5);
	if (ret < 0) ERR_EXIT("listen");

	cliaddrlen = sizeof(cliaddr);
	clientfd = accept(listenfd, (struct sockaddr*)&cliaddr, &cliaddrlen);
	if (clientfd < 0) ERR_EXIT("accept");

	printf("%s:%d come in\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));

	readn(clientfd, (char*)&ss, sizeof(ss));

	length = ss.length;
	number = ss.number;
	printf("length = %d, number = %d\n", length, number);

	msg = (struct message*)malloc(ss.length + sizeof(int));
	assert(msg);
	for (i = 0; i < ss.number; ++i) {
    readn(clientfd, (char*)msg, ss.length + sizeof(int));
    ack = msg->length;
		writen(clientfd, (char*)&ack, sizeof(int));
	}
	close(clientfd);
	close(listenfd);
	free(msg);
}

static void client_routine() {
  int ret, clientfd, i, ack;
  int64_t	start;
  double total_mb;
	struct sockaddr_in servaddr;
	struct session ss;
	struct message *msg;

	printf("length = %d, number = %d\n", length, number);
	ss.length = length;
	ss.number = number;
	total_mb = 1.0 * length * number / 1024 / 1024; 

	msg = (struct message*)malloc(length + sizeof(int));
	assert(msg);
	msg->length = length;
	for (i = 0; i < length; ++i) {
		msg->data[i] = "0123456789ABCDEFG"[i%16];
	}

	servaddr = resolve(hostname, port);
	clientfd = socket(AF_INET, SOCK_STREAM, 0);
	if (clientfd < 0) ERR_EXIT("socket");

	ret = connect(clientfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
  if (ret < 0) ERR_EXIT("connect");
	puts("connect successfully!");
  
	start = now();
	writen(clientfd, (char*)&ss, sizeof(ss)); 

	for (i = 0; i < number; ++i) {
		writen(clientfd, (char*)msg, length + sizeof(int));
		readn(clientfd, (char*)&ack, sizeof(int));
		assert(ack == length);
	}

	double elapsed = (now() - start) / 1000000.0;
	printf("%f MB translated, %f s, %f MB/s\n", total_mb, elapsed, total_mb / elapsed); 
	printf("throughout: %f msg/s\n", number / elapsed); 
	close(clientfd);
	free(msg);
}
